/*
 * Created on 08/30/2011 - 11:38 PM
 */
package sembr.vtk.visualizing;

import sembr.vtk.data.input.SourceBase;
import sembr.vtk.mesh.MesherBase;
import sembr.vtk.reader.ReaderBase;
import vtk.*;

/**
 * @author Adriano
 */
public class VtkVisualizationManager 
{
    private SourceBase inputData;
    private ReaderBase reader;
    private vtkAppendPolyData appendPolyData;
    private vtkPolyDataMapper polyDataMapper;
    private vtkPolyDataMapper outlineMapper;
    private vtkDataSetMapper dataSetMapper;
    private vtkOutlineFilter outline;
    private vtkActor surfaceActor;
    private vtkActor solidActor;
    private vtkActor outlineActor;
    private vtkCubeAxesActor pmlDomainActor;
    private vtkCamera camera1;
    private vtkCamera camera2;
    private vtkCamera camera3;
    private vtkCamera camera4;
    private VtkMultRenderPanel multRenderPanel;
            
    /**
     * Constructor for surface
     * @param inputData 
     */
    public VtkVisualizationManager(SourceBase inputData)
    {
        this.inputData = inputData;
        polyDataMapper = new vtkPolyDataMapper();
        surfaceActor = new vtkActor();  
        camera1 = new vtkCamera();    
        camera2 = new vtkCamera();
        camera3 = new vtkCamera();
        camera4 = new vtkCamera();
        multRenderPanel = new VtkMultRenderPanel();
    }
    
    public VtkVisualizationManager(MesherBase mesh)
    {
        setUnstructuredGridMapper(mesh);
        solidActor = new vtkActor();
        camera1 = new vtkCamera();    
        camera2 = new vtkCamera();
        camera3 = new vtkCamera();
        camera4 = new vtkCamera();
        multRenderPanel = new VtkMultRenderPanel();
    }
    
    public VtkVisualizationManager(ReaderBase reader)
    {
        this.reader = reader;
        polyDataMapper = new vtkPolyDataMapper();
        surfaceActor = new vtkActor();  
        camera1 = new vtkCamera();    
        camera2 = new vtkCamera();
        camera3 = new vtkCamera();
        camera4 = new vtkCamera();
        multRenderPanel = new VtkMultRenderPanel();
    }
        
    /**
    * VtkVisualizationManager´s vtkPanel property
    * getMultRenderPanel() exposes vtkPanel to interact with Panel from GUI
    * @return the multRenderPanel
    */
    public VtkMultRenderPanel getMultRenderPanel() 
    {
        return multRenderPanel;
    }
    
    public void setAppendPolydata(vtkAppendPolyData appender) {
        this.appendPolyData = appender;
    }
    
    public void addPolydata(vtkPolyData currentPolyData) {
        if (this.appendPolyData == null) 
            this.appendPolyData = new vtkAppendPolyData();
        
        this.appendPolyData.AddInput(currentPolyData);
        this.appendPolyData.Update();
    }
    
    public vtkPolyData getAppendedPolyData()
    {
        return this.appendPolyData.GetOutput();
    }
       
    /**
     * VTK system execution is determined by pipeline process.
     * VTK pipeline needs to respect the order of execution.
     * Generally, VTK system gets the source data objects,
     * instanciates the appropriate forms and may transform it.
     * After transforming, VTK mapps the new object, creates the
     * actor and scene to render the graphics.
    */
    public void processPipeline(boolean propertyVisibility)
    {
        if (appendPolyData != null && appendPolyData.GetOutput() != null)
        {
            setPolyDataMapper(appendPolyData.GetOutput(), propertyVisibility);           
            setSurfaceActor();
        }
        else if (inputData != null)
        {
            setPolyDataMapper(inputData.getPolyData(), propertyVisibility);           
            setSurfaceActor();
        }
        else if (reader != null)
        {
            setPolyDataMapper(reader.getPolyData(), propertyVisibility);
            setSurfaceActor();
        }
        else
        {
            setSolidActor();
        }
        setCamera1();
        //setCamera2();
        //setCamera3();
        //setCamera4();
        setMultRenderPanel();
    }   
    
    public SourceBase getInputData()
    {
        return this.inputData;
    }
        
    /**
     * VtkVisualizationManager receives polydatas from VtkDataReceiver
     * It needs to append all polydatas to construct a unique shape
    */
    
    public void setOutlineDomain(vtkPolyData pd)
    {
        outline = new vtkOutlineFilter();
        outline.SetInput(pd);   
        outline.Update();
    }
    
    private void setPolyDataMapper(vtkPolyData polydata, boolean scalarVisibility)
    {         
        polyDataMapper.SetInput(polydata);  
        
       // if (scalarVisibility)
      //      polyDataMapper.ScalarVisibilityOn();
       // else
            polyDataMapper.ScalarVisibilityOff();
        
        if (outline != null)
        {
            outlineMapper = new vtkPolyDataMapper();
            outlineMapper.SetInputConnection(this.outline.GetOutputPort());
            outlineMapper.Update();
        }
        
        polyDataMapper.Update();
    }
    
    private void setUnstructuredGridMapper(MesherBase currentMesh)
    {
        dataSetMapper = new vtkDataSetMapper();
        dataSetMapper.SetInput(currentMesh.getUnstructuredGrid());        
    }
    
    /**
     * @return the pmlDomainActor
     */
    public vtkCubeAxesActor getPmlDomainActor() 
    {
        return pmlDomainActor;
    }

    /**
     * @param pmlDomainActor the pmlDomainActor to set
     */
    public void setPmlDomainActor(double[] bounds) 
    {
        vtkProperty property = new vtkProperty();
        property.SetColor(0., 0., 0.);
        
        pmlDomainActor = new vtkCubeAxesActor();
        pmlDomainActor.SetBounds(bounds);
        pmlDomainActor.SetCamera(camera1);
        pmlDomainActor.SetFlyModeToOuterEdges();
        
        pmlDomainActor.GetXAxesLinesProperty().SetColor(0., 0., 0.);
        pmlDomainActor.GetTitleTextProperty(0).SetColor(0., 0., 0.);
        pmlDomainActor.GetLabelTextProperty(0).SetColor(0., 0., 0.);
        
        pmlDomainActor.GetYAxesLinesProperty().SetColor(0., 0., 0.);
        pmlDomainActor.GetTitleTextProperty(1).SetColor(0., 0., 0.);
        pmlDomainActor.GetLabelTextProperty(1).SetColor(0., 0., 0.);
        
        pmlDomainActor.GetZAxesLinesProperty().SetColor(0., 0., 0.);
        pmlDomainActor.GetTitleTextProperty(2).SetColor(0., 0., 0.);
        pmlDomainActor.GetLabelTextProperty(2).SetColor(0., 0., 0.);
    }
    
    private void setSurfaceActor()
    {
        surfaceActor.SetMapper(this.polyDataMapper);
        surfaceActor.GetProperty().SetColor(0.3, 0.3, 0.3);
        surfaceActor.GetProperty().SetOpacity(0.7);
            
        if (outline != null)
        {
            outlineActor = new vtkActor();
            outlineActor.SetMapper(this.outlineMapper);
            outlineActor.GetProperty().SetColor(0.5, 0.5, 0.5);
        }      
    }
    
    private void setSolidActor()
    {
        solidActor.SetMapper(dataSetMapper);
        solidActor.SetOrigin(0.00, 0.00, 0.00); 
        solidActor.GetProperty().SetColor(0., 0., 0.);
    }
    
    private void setCamera1()
    {
        camera1.SetViewUp(0.00, 1.00, 0.00);
        camera1.SetPosition(2, 2, 2);
        camera1.SetFocalPoint(0, 0, 0);  
        camera1.Azimuth(0.00);
    }
    
    private void setCamera2()
    {
        camera2.SetViewUp(0.00, 1.00, 0.00);
        camera2.SetPosition(2, 2, 2);
        camera2.SetFocalPoint(0, 0, 0); 
        camera2.Azimuth(90.00);
    }
    
    private void setCamera3()
    {
        camera3.SetViewUp(0.00, 1.00, 0.00);
        camera3.SetPosition(2, 2, 2);
        camera3.SetFocalPoint(0, 0, 0); 
        camera3.Azimuth(180.00);
    }
    
    private void setCamera4()
    {
        camera4.SetViewUp(0.00, 1.00, 0.00);
        camera4.SetPosition(0, 0, 0);
        camera4.SetFocalPoint(0, 0, 0); 
        camera4.Azimuth(270.00);       
    }
    
    public void addActorToPanel(vtkProp3D currentActor)
    {
        // add actor to the four panel's renderers
        multRenderPanel.GetRenderer().AddActor(currentActor);
        multRenderPanel.getRenderer2().AddActor(currentActor);
        multRenderPanel.getRenderer3().AddActor(currentActor);
        multRenderPanel.getRenderer4().AddActor(currentActor);
    }
        
    public void setMultRenderPanel()
    {
        if (surfaceActor != null)
            addActorToPanel(surfaceActor);
            
        if (solidActor != null)
            addActorToPanel(surfaceActor);
                
        if (outline != null) 
            addActorToPanel(outlineActor);
        
        if (getPmlDomainActor() != null)
            addActorToPanel(getPmlDomainActor());      
                
        // set renderers´camera
        multRenderPanel.GetRenderer().SetActiveCamera(camera1);
        multRenderPanel.getRenderer2().SetActiveCamera(camera1);
        multRenderPanel.getRenderer3().SetActiveCamera(camera1);
        multRenderPanel.getRenderer4().SetActiveCamera(camera1);
    }   
}
